import logging
import os
import threading

from PyQt5 import QtGui
from PyQt5.QtBluetooth import QBluetoothDeviceInfo, QBluetoothDeviceDiscoveryAgent, QLowEnergyController, \
    QBluetoothUuid
from PyQt5.QtCore import QCoreApplication, Qt, pyqtSignal
from PyQt5.QtGui import QPixmap, QIcon, QTextCursor
from PyQt5.QtWidgets import QMainWindow, QListWidgetItem

from app_config import app_gl_config, resource_icon_path
from common import set_widget, APP_NORMAL_MSG, APP_ERROR_MSG
from widget.device_widget import add_new_device_item, DeviceInfoWidget
from widget.main_window_ui import Ui_MainWindow


class MainWindow(QMainWindow, Ui_MainWindow):
    msg_update = pyqtSignal(int, str)
    filter_info_updated = pyqtSignal(QBluetoothDeviceInfo)

    def __init__(self):
        super(MainWindow, self).__init__()
        self.device_cache = []  # 临时缓存设备信息，用于过滤
        self.setupUi(self)
        self._custom_ui()
        self._signal_init()
        self._thread_init()
        # Initialize for BLE
        self.device_discovery_agent = QBluetoothDeviceDiscoveryAgent(self)
        self._ble_signal_init()
        set_widget('main_widget', self)

    def _custom_ui(self):
        icon = QIcon()
        icon.addPixmap(QPixmap(os.path.join(resource_icon_path, 'ble.png')))
        self.setWindowIcon(icon)
        self.adv_detail_widget.hide()

    def _signal_init(self):
        # 过滤
        self.filter_le.textChanged.connect(self.on_filter_text_changed)
        self.scan_ctl_pb.clicked.connect(self.on_scan_ctl_button_clicked)
        self.device_info_list.itemClicked.connect(self.on_ble_device_item_clicked)
        self.back_to_device_list_pb.clicked.connect(self.on_back_to_device_detail_clicked)
        # tab关闭
        self.device_tw.tabCloseRequested.connect(self.on_device_tab_close_request)
        # log
        self.msg_update.connect(self.on_msg_update)
        # 更新BLE设备信息
        self.filter_info_updated.connect(self.on_device_list_update)

    def _ble_signal_init(self):
        self.device_discovery_agent.deviceDiscovered.connect(self.add_device)
        self.device_discovery_agent.error.connect(self.scan_error)
        self.device_discovery_agent.finished.connect(self.scan_finished)
        self.device_discovery_agent.canceled.connect(self.scan_finished)

    def _thread_init(self):
        self.filter_new_event = threading.Event()
        self.filter_thread = threading.Thread(target=self.filter_thread_entry)
        self.filter_thread.start()

    def on_filter_text_changed(self, filter_name: str):
        if not self.filter_new_event.is_set():
            self.filter_new_event.set()
        # 过滤信息改变清空列表
        self.device_info_list.clear()
        # 如果过滤信息为空,把所有设备添加到UI
        if filter_name == "":
            for device in self.device_cache:
                add_new_device_item(self.device_info_list, QBluetoothDeviceInfo(device))

    def on_scan_ctl_button_clicked(self):
        self.msg_print("start scan")
        if self.scan_ctl_pb.text() == "扫描":
            self.scan_ctl_pb.setText("停止")
            self.device_info_list.clear()
            self.device_cache.clear()
            try:
                timeout: int = int(self.scan_timeout_sp.value())
                app_gl_config.args['ScanTimeout'] = timeout

                self.ble_config(timeout)
                # self.device_discovery_agent.start(QBluetoothDeviceDiscoveryAgent.DiscoveryMethod(2))
                self.device_discovery_agent.start()

                app_gl_config.save_user_config()
            except Exception as e:
                self.msg_print(str(e), APP_ERROR_MSG)
        elif self.scan_ctl_pb.text() == "停止":
            self.device_discovery_agent.stop()
            self.scan_ctl_pb.setText("扫描")

    def on_ble_device_item_clicked(self, item: QListWidgetItem):
        try:
            print("item clicked")
            self.device_info_te.clear()
            self.device_info_list.hide()
            self.adv_detail_widget.show()
            w: DeviceInfoWidget = self.device_info_list.itemWidget(item)
            device_info = w.device_info
            if device_info.coreConfigurations() == 1:
                dev_type = "Bluetooth low energy device"
            elif device_info.coreConfigurations() == 2:
                dev_type = "Bluetooth standard device"
            else:
                dev_type = "Bluetooth standard and low energy device"
            self.device_info_te.setText("Device name: " + device_info.name() +
                                        "\nDevice type: " + dev_type +
                                        "\nMAC address: " + device_info.address().toString() +
                                        "\nDevice UUID: " + device_info.deviceUuid().toString() + '\n')
        except Exception as e:
            logging.error(e)
            self.msg_print(str(e), APP_ERROR_MSG)

    def on_back_to_device_detail_clicked(self):
        self.adv_detail_widget.hide()
        self.device_info_list.show()

    def on_device_tab_close_request(self, index):
        if index != 0:
            self.device_tw.removeTab(index)

    def on_msg_update(self, level, msg):
        self.msg_te.moveCursor(QTextCursor.End)
        if level == APP_NORMAL_MSG:
            self.msg_te.append("<font color=\"#000000\">{id}:{msg}</font>".format(id="Normal", msg=msg))  # 黑色
        elif level == APP_ERROR_MSG:
            self.msg_te.append("<font color=\"#FF0000\">{id}:{msg}</font>".format(id="error", msg=msg))  # 红色
        else:
            self.msg_te.append("<font color=\"#00FF00\">{id}:{msg}</font>".format(id="import", msg=msg))  # 绿色
        self.msg_te.moveCursor(QTextCursor.End)

    def on_device_list_update(self, device: QBluetoothDeviceInfo):
        add_new_device_item(self.device_info_list, QBluetoothDeviceInfo(device))

    def msg_print(self, msg: str, level=0):
        self.msg_update.emit(level, msg)

    def ble_config(self, timeout: int):
        self.device_discovery_agent.setLowEnergyDiscoveryTimeout(timeout)

    def add_device(self, device: QBluetoothDeviceInfo):
        # If device is LowEnergy-device, add it to the list
        try:
            if device.coreConfigurations() == QBluetoothDeviceInfo.LowEnergyCoreConfiguration:
                self.device_cache.append(QBluetoothDeviceInfo(device))
                # 过滤列表为空,或者设备名字匹配，把设备信息载入UI
                if self.filter_le.text() in device.name() or self.filter_le.text() == "":
                    add_new_device_item(self.device_info_list, QBluetoothDeviceInfo(device))
                self.msg_print("find device:" + device.name())
                return
        except Exception as e:
            self.msg_print(str(e), APP_ERROR_MSG)

    def scan_finished(self):
        self.msg_print("scan finished")
        self.scan_ctl_pb.setText("扫描")
        # TODO:加入扫描等待结束动画

    def scan_error(self):
        self.msg_print("scan error", APP_ERROR_MSG)
        self.scan_ctl_pb.setText("扫描")

    def closeEvent(self, a0: QtGui.QCloseEvent) -> None:
        try:
            self.device_discovery_agent.stop()
            print("stop discovery")
        except Exception as e:
            print(e)
        super().closeEvent(a0)

    def filter_thread_entry(self):
        """
        过滤设备的线程
        :return: 
        """
        while True:
            self.filter_new_event.wait()
            self.filter_new_event.clear()  # 必须手动清除
            for device in self.device_cache:
                if self.filter_le.text() in device.name():
                    # 找到过滤设备添加到UI
                    self.filter_info_updated.emit(device)
                    break  # 退出for循环,线程一直都在
